<?php
/**
 * 	Bushido
 *
 * @category   Bushido
 * @package    Bushido_ColorPalette
 * @copyright  Copyright (c) 2008-2009 Nathan Keyes
 * @author Nathan Keyes
 * @version    $Id: ColorPalette.php 7 2009-11-14 22:42:08Z nkeyes $
 */

/**
 * 
 * @author Nathan Keyes
 *
 */
class Bushido_ColorPalette
{
	
	/**
	 * 
	 * @return void
	 */
	public function __construct(){}
	
	/**
	 * 
	 * @return void
	 */
	public function __clone(){}
	
	/**
	 * 
	 * @param array $color 
	 * @return array
	 */
	public static function rgb2hsv($color)
	{
		if(!isset($color['r']) || !isset($color['g']) || !isset($color['b']))
		{
			throw new Exception('$color must be an array containing the keys r, g and b with numeric values');
		}
		$r = $color['r'] / 255;
		$g = $color['g'] / 255;
		$b = $color['b'] / 255;
		
		$min = min($r,$g,$b);
		$max = max($r,$g,$b);
		
		$delta = $max - $min;
		
		$v = $max;
		
		if($delta == 0)
		{
			$h = 0;
			$s = 0;
		}
		else
		{
			$s = $delta / $max;
			$deltaRed = ((($max - $r)/6)+($delta/2))/$delta;
			$deltaGreen = ((($max - $g)/6)+($delta/2))/$delta;
			$deltaBlue = ((($max - $b)/6)+($delta/2))/$delta;
			
			if($r == $max)
			{
				$h = $deltaBlue - $deltaGreen;
			}
			elseif($g == $max)
			{
				$h = (1/3) + $deltaRed - $deltaBlue;
			}
			elseif($b == $max)
			{
				$h = (2/3) + $deltaGreen - $deltaRed;
			}
			
			$h = $h < 0 ? $h + 1 : $h;
			$h = $h > 1 ? $h - 1 : $h;
			
		}
		
		return array('h' => $h, 's' => $s, 'v' => $v);
	}
	
	/**
	 * 
	 * @param array $color
	 * @return array
	 */
	public static function hsv2rgb($color)
	{
		if(!isset($color['h']) || !isset($color['s']) || !isset($color['v']))
		{
			throw new Exception('$color must be an array containing the keys h, s and v with numeric values');
		}
		$h = $color['h'];
		$s = $color['s'];
		$v = $color['v'];
		
		if($s == 0)
		{
			$r = $v * 255;
			$g = $v * 255;
			$b = $v * 255;
		}
		else
		{
			$h *= 6;
			$h = $h == 6 ? 0 : $h;
			
			$floor_h = floor($h);
			
			$val1 = $v * (1 - $s);
			$val2 = $v * (1 - $s * ($h - $floor_h));
			$val3 = $v * ( 1 - $s * ( 1 - ( $h - $floor_h ) ) );
			
			switch($floor_h)
			{
				case 0:
					$r = $v;
					$g = $val3;
					$b = $val1;
					break;
				case 1:
					$r = $val2;
					$g = $v;
					$b = $val1;
					break;
				case 2:
					$r = $val1;
					$g = $v;
					$b = $val3;
					break;
				case 3:
					$r = $val1;
					$g = $val2;
					$b = $v;
					break;
				case 4:
					$r = $val3;
					$g = $val1;
					$b = $v;
					break;
				default:
					$r = $v;
					$g = $val1;
					$b = $val2;
					break;
			}
			
			
			$r *= 255;
			$g *= 255;
			$b *= 255;


		}
		$r = round($r);
		$g = round($g);
		$b = round($b);
		
		return array('r' => $r, 'g' => $g, 'b' => $b);
	}
	
	/**
	 * 
	 * @param array $color
	 * @param int $percent
	 * @return array
	 */
	public static function lightenColor($color, $amount)
	{
		$color = self::rgb2hsv($color);
						
		$amount /= 100;

		if($color['s'] > 0)
		{
			$color['s'] -= $amount;
			//$color['s'] = $color['s'] > 1 ? $color['s'] - 1 : $color['s'];
			$color['s'] = $color['s'] > 1 ? 1 : $color['s'];
			//$color['s'] = $color['s'] < 0 ? $color['s'] + 1 : $color['s'];
			$color['s'] = $color['s'] < 0 ? 0 : $color['s'];
		}
		
		$color['v'] += $amount;
		
		//$color['s'] = $color['s'] > 1 ? $color['s'] - 1 : $color['s'];
		$color['s'] = $color['s'] > 1 ? 1 : $color['s'];
		//$color['s'] = $color['s'] < 0 ? $color['s'] + 1 : $color['s'];
		$color['s'] = $color['s'] < 0 ? 0 : $color['s'];
		
		$color = self::hsv2rgb($color);
		return $color;
	}
	
	
	/**
	 * 
	 * @param array $color
	 * @param int $percent
	 * @return array
	 */
	public static function darkenColor($color, $amount)
	{
		return self::lightenColor($color, $amount * -1);
		
	}
	
	
	/**
	 * 
	 * @param $color
	 * @return array a three-element array of the supplied color and the colors completing the triad harmony
	 */
	public static function triad($color)
	{
		return self::_triplet($color, 120);
	}
	
	
	/**
	 * 
	 * @param $color
	 * @return array a three-element array of the supplied color and the 2 colors completing the split compliments harmony
	 */
	public static function split_compliments($color)
	{
		return self::_triplet($color, 150);
	}
	
	
	/**
	 * 
	 * @param $color
	 * @return array a three-element array of the supplied color and the 2 colors completing the analogues harmony
	 */
	public static function analogues($color)
	{
		return self::_triplet($color, 30);
	}
	
	
	/**
	 * 
	 * @param $color
	 * @param $angle
	 * @return array the color and its compliment
	 */
	public static function compliment($color)
	{
		return self::hue_shift($color, 180);
	}
	
	
	/**
	 * 
	 * @param $color
	 * @param $angle
	 * @return array new color hue shifted by $angle
	 */
	public static function hue_shift($color, $angle)
	{
		$shiftDelta = $angle / 360;
		
		$hsvColor = self::rgb2hsv($color);

		$shiftedColor = $hsvColor;
		
		$shiftedColor['h'] += $shiftDelta;
		
		$shiftedColor['h'] = $shiftedColor['h'] > 1 ? $shiftedColor['h'] - 1 : $shiftedColor['h'];
		$shiftedColor['h'] = $shiftedColor['h'] < 0 ? $shiftedColor['h'] + 1 : $shiftedColor['h'];
		
		return self::hsv2rgb($shiftedColor);
	}
	
	/**
	 * 
	 * @param $color
	 * @param $angle
	 * @return array
	 */
	protected static function _triplet($color, $angle)
	{
		$tripletPlusColor = self::hue_shift($color, $angle);
		$tripletMinusColor = self::hue_shift($color, $angle * -1);
		
		return array
		(
			'color' => $color,
			'plusColor' => $tripletPlusColor,
			'minusColor' => $tripletMinusColor,
		);
	}
}
